package user03.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import common05.common.Results;
import common05.common.Token;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import user03.mapper.TUserMapper;
import user03.model.TUser;
import user03.vo.LoginUserVO;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class TUserService extends ServiceImpl<TUserMapper, TUser> {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private JwtEncoder encoder;

    @Autowired
    private TUserRoleService tUserRoleService;

    @Autowired
    private TRoleMenuService tRoleMenuService;

    @Autowired
    private TMenuService tMenuService;

    public TUser selectByUsername(String username) {
        QueryWrapper<TUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        List<TUser> list = list(wrapper);
        if (list == null || list.size() != 1) {
            return null;
        }
        return list.get(0);
    }

    public Results login(LoginUserVO vo) {
        TUser tUser = selectByUsername(vo.getUsername());
        if (tUser == null) {
            return Results.param_error("用户名或密码错误");
        }
        if (!(DigestUtils.sha256Hex(vo.getPassword())).equals(tUser.getPassword())) {
            return Results.param_error("用户名或密码错误");
        }

        if (tUser.getEnable() == 0) {
            return Results.param_error("用户禁止登录");
        }

        List<Long> roleIds = tUserRoleService.selectRoleIdsByUserId(tUser.getId());
        List<Long> menuIds = tRoleMenuService.selectMenuIdsByRoleId(roleIds);
        List<String> urls = tMenuService.selectUrlListByIds(menuIds);
        String scope = "";
        if (urls != null && urls.size() > 0) {
            scope = String.join(" ", urls);
        }

        Instant now = Instant.now();
        Instant expTime = now.plusMillis(Token.LOGIN_EXPIRY_MILLIS_NUM);

        JwtClaimsSet claims = JwtClaimsSet.builder()
                .issuer(Token.JWT_ISS)
                .issuedAt(now) //注册时间
                .expiresAt(expTime) //过期时间
                .subject(String.valueOf(tUser.getId()))
                .claim("scope", scope)
                .build();

        String tokenValue = encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();

        stringRedisTemplate.opsForValue().set(Token.getTokenRedisKey(tUser.getId()), tokenValue, Token.LOGIN_EXPIRY_MILLIS_NUM, TimeUnit.MILLISECONDS);

        return Results.success(tokenValue);
    }

    public boolean updatePasswordById(Long userId, String newPassword) {
        UpdateWrapper<TUser> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", userId);
        wrapper.set("password", DigestUtils.sha256Hex(newPassword));
        return update(wrapper);
    }

    /**
     * 用户有效/无效  enable=0无效  enable=1有效
     */
    public Boolean changeUserEnableStatus(Long userId, Integer enable) {
        if (userId == null || enable == null || (enable != 0 && enable != 1)) {
            return false;
        }
        UpdateWrapper<TUser> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", userId);
        wrapper.set("enable", enable);
        boolean update = update(wrapper);
        if (update && enable == 0) {
            kickUserOff(userId);
        }
        return update;
    }


    /**
     * 踢人下线
     */
    public Boolean kickUserOff(Long userId) {
        log.info("踢人下线  userId=[{}]", userId);
        return stringRedisTemplate.delete(Token.getTokenRedisKey(userId));
    }


    /**
     * 更新用户对应的角色
     */
    public Boolean updateUserRoles(Long userId, List<Long> roleIds) {
        Boolean updateUserRoles = tUserRoleService.updateUserRoles(userId, roleIds);
        if (updateUserRoles) {
            kickUserOff(userId);
        }
        return updateUserRoles;
    }

    public Long getCurrentUserId() {
        return Long.parseLong(request.getHeader("userId"));
    }

    public TUser getCurrentUser() {
        return getById(getCurrentUserId());
    }
}
